package genedit.view.graph;

import genedit.gui.GMainFrame;
import genedit.model.Workspace;
import genedit.model.graph.GraphDocument;
import genedit.model.graph.GraphElement;
import genedit.model.graph.Link;
import genedit.model.graph.Point;
import genedit.model.graph.SubdocumentElement;
import genedit.utility.GraphUtil;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;



public class SelectionHandleHandler {

	static final int handleSize = 6;
	
	public enum Handle {

		North, South, East, West, SouthEast, SouthWest, NorthEast, NorthEastEast, NorthWest

	}
	/**
	 * Iscrtavanje selekcionih hendlova oko selektovanih elemenata. VeliÄ�ina
	 * hendlova i debljina isprekidane linije ne zavise od tekuÄ‡eg skaliranja.
	 */
	void paintSelectionHandles(Graphics2D g2, GraphDocument selection, double scale) {

		Iterator<GraphElement> iter = selection.getIteratorSelectedElements();
		Stroke backupStroke=g2.getStroke();
		Color backupColor=g2.getColor();
		AffineTransform backupTransformation;
		g2.setStroke(new BasicStroke(1 / (float) scale, BasicStroke.CAP_SQUARE,
				BasicStroke.JOIN_BEVEL, 1f, new float[] { 3f, 6f }, 0));
		g2.setPaint(Color.BLACK);
		
		while (iter.hasNext()) {
			GraphElement elem = iter.next();
			backupTransformation=g2.getTransform();
			
			if (!(elem instanceof genedit.model.graph.Link)) {
				// Iscrtavanje pravougaonika sa isprekidanom linijom
				ElementPainter elementPainter=GMainFrame.getInstance()
						.getGraphDocumentView((GraphDocument)elem.getParent()).getPainter(elem);
				g2.transform(elementPainter.getTransform());
				g2.drawRect(0,0,(int)elem.getSize().getWidth(), (int) elem.getSize().getHeight());

				// Iscrtavanje hendlova
				for (Handle e : Handle.values()) {
					if (e != Handle.NorthEastEast)
						paintSelectionHandle(g2,
								getHandlePoint(elem.getSize(), e), scale);
					else
						paintSelectionHandle(g2,
								getHandlePoint(elem.getSize(), e), 2);
				}
			} else {
				Link lp = (Link) elem;
				for (Point p : ((Link) lp).getAllPoints())
					paintSelectionHandle(g2, p.getPosition(), scale);
			}
			g2.setTransform(backupTransformation);
		}
		
		g2.setStroke(backupStroke);
		g2.setColor(backupColor);
	}

	/**
	 * Iscrtavanje jednog selekcionog hendla za zadatu poziciju
	 */
	private void paintSelectionHandle(Graphics2D g2, Point2D position, double scale) {
		double size = handleSize / scale;
		g2.fill(new Rectangle2D.Double(position.getX() - size / 2, position.getY() - size / 2,
				size, size));
	}

	/**
	 * Pronalazi tačku na kojoj se hendl nalazi za zadatu poziciju i veličinu
	 * elementa
	 * 
	 * @param topLeft
	 *            - pozicija elementa
	 * @param size
	 *            - veliÄ�ina elementa
	 * @param handlePosition
	 *            - hendl koji nas interesuje
	 * @return taÄ�ka u kojoj se hendl nalazi
	 */
	private Point2D getHandlePoint(Dimension2D size, Handle handlePosition) {
		double x = 0, y = 0;

		if (handlePosition == Handle.NorthEastEast) {
			y = - 10;
			x = size.getWidth() + 20;
		}

		// OdreÄ‘ivanje y koordinate

		// Ako su gornji hendlovi
		if (handlePosition == Handle.NorthWest || handlePosition == Handle.North
				|| handlePosition == Handle.NorthEast) {
			y = 0;
		}

		// Ako su centralni po y osi
		if (handlePosition == Handle.East || handlePosition == Handle.West) {
			y =  size.getHeight() / 2;
		}

		// Ako su donji
		if (handlePosition == Handle.SouthWest || handlePosition == Handle.South
				|| handlePosition == Handle.SouthEast) {
			y = size.getHeight();
		}

		// OdreÄ‘ivanje x koordinate

		// Ako su levi
		if (handlePosition == Handle.NorthWest || handlePosition == Handle.West
				|| handlePosition == Handle.SouthWest) {
			x = 0;
		}

		// ako su centralni po x osi
		if (handlePosition == Handle.North || handlePosition == Handle.South) {
			x = size.getWidth() / 2;
		}

		// ako su desni
		if (handlePosition == Handle.NorthEast || handlePosition == Handle.East
				|| handlePosition == Handle.SouthEast) {
			x = size.getWidth();
		}

		return new Point2D.Double(x, y);
	}

	/**
	 * Za zadatu taÄ�ku i element vraÄ‡a hendl.
	 * 
	 * @param device
	 * @param point
	 * @return Hendl ukoliko je "pogođen", u suprotnom vrađa null
	 */
	public Handle getHandleForPoint(GraphElement elem, Point2D point, double scale) {
		Point2D objectSpacePoint=(Point2D)point.clone();
		ElementPainter elementPainter=GMainFrame.getInstance()
				.getGraphDocumentView((GraphDocument)elem.getParent()).getPainter(elem);
		GraphUtil.inverseTransform(elementPainter.getTransform(), objectSpacePoint);
		for (Handle h : Handle.values()) {
			if (isPointInHandle(elem, objectSpacePoint, h, scale)) {
				return h;
			}
		}
		return null;
	}

	public Handle getHandleForRotate() {
		return Handle.NorthEastEast;
	}

	/**
	 * Za zadati ureÄ‘aj, taÄ�ku i hendl odreÄ‘uje da li je taÄ�ka unutar hendla
	 */
	private boolean isPointInHandle(GraphElement elem, Point2D point, Handle handle, double scale) {
		Point2D handleCenter = getHandlePoint(elem.getSize(), handle);
		
		return ((Math.abs(point.getX() - handleCenter.getX()) <= (double) handleSize / 2 / scale) && (Math
				.abs(point.getY() - handleCenter.getY()) <= (double) handleSize / 2 / scale));
		

	}
}
